NLLLossGrad ================= ``NLLLoss`` 的反向:由上游损失梯度反传得到对 logits / log_probs 的梯度。 仅在真实类别位置写入非零值,其余类别位置为 0。 设 batch 为 :math:`N`,类别数为 :math:`C`。``logits`` / ``logits_grad`` 形状为 :math:`N \times C`,``labels`` 长度为 :math:`N`,``weight`` 长度为 :math:`C`。 ``logits`` 仅占位,计算不读其数值。 对样本 :math:`i`,令 :math:`y_i = \mathrm{labels}[i]`,:math:`w_i = \mathrm{weight}[y_i]`, :math:`W = \mathrm{total\_weight}`。先将 ``logits_grad`` 清零,再写: .. math:: \mathrm{logits\_grad}[i, y_i] = \begin{cases} -\,\mathrm{loss\_grad}[0] \cdot w_i, & \mathrm{reduction}=0\ \text{(Sum)} \\ -\,\mathrm{loss\_grad}[0] \cdot w_i / W, & \mathrm{reduction}=1\ \text{(Mean)} \\ -\,\mathrm{loss\_grad}[i] \cdot w_i, & \mathrm{reduction}=2\ \text{(None)} \end{cases} reduction_type 约定(本算子编码,与前向 ``NLLLoss`` 不同): - ``0``:Sum,使用标量 ``loss_grad[0]`` - ``1``:Mean,使用标量 ``loss_grad[0]`` 与 ``total_weight`` - ``2``:None,使用逐样本 ``loss_grad[i]`` 输入: - **logits** - 前向输入地址,形状 ``[batch, class_num]``,不参与数值计算 - **loss_grad** - 上游梯度;Sum / Mean 时用 ``loss_grad[0]``,None 时长度为 ``batch`` - **labels** - 标签索引,形状 ``[batch]`` - **params** - ``long long`` 参数数组,长度至少 5,布局见下 - **core_mask** - 核掩码(仅共享存储版本使用) **params 布局:** - ``[0]`` ``weight`` - 类别权重数组地址 - ``[1]`` ``total_weight`` - 权重和地址,Mean 时使用 - ``[2]`` ``batch`` - batch 大小 :math:`N` - ``[3]`` ``class_num`` - 类别数 :math:`C` - ``[4]`` ``reduction_type`` - 归约方式,取值 ``{0,1,2}`` 输出: - **logits_grad** - 输出梯度,形状 ``[batch, class_num]`` 支持平台: ``FT78NE`` ``MT7004`` .. note:: - FT78NE 支持 fp32 - MT7004 支持 fp16、fp32 - ``labels[i]`` 需满足 :math:`0 \le y_i < C` - 本算子 ``reduction_type`` 为 ``0/1/2``,即 Sum / Mean / None;与前向 ``NLLLoss`` 的 ``0/1/2``,即 None / Sum / Mean 不一致,调用时勿混用 **共享存储版本:** .. c:function:: void hp_nll_loss_grad_s(float16 *logits, float16 *loss_grad, int *labels, float16 *logits_grad, long long *params, int core_mask) .. c:function:: void fp_nll_loss_grad_s(float *logits, float *loss_grad, int *labels, float *logits_grad, long long *params, int core_mask) **C调用示例:** .. code-block:: c :linenos: :emphasize-lines: 19 // MT7004 示例(共享存储多核,DDR 地址) void TestNllLossGradSMCFp32(int core_mask) { int core_id = get_core_id(); int logic_core_id = GetLogicCoreId(core_mask, core_id); int core_num = GetCoreNum(core_mask); float *logits = (float *)0x81000000; float *loss_grad = (float *)0x82000000; int *labels = (int *)0x83000000; float *weight = (float *)0x84000000; float *total_weight = (float *)0x85000000; float *logits_grad = (float *)0x86000000; long long params[5]; params[0] = (long long)weight; params[1] = (long long)total_weight; params[2] = 16; // batch params[3] = 16; // class_num params[4] = 2; // reduction_type = None sys_bar(0, core_num); fp_nll_loss_grad_s(logits, loss_grad, labels, logits_grad, params, core_mask); } void main() { int core_mask = 0b1111; TestNllLossGradSMCFp32(core_mask); } **私有存储版本:** .. c:function:: void hp_nll_loss_grad_p(float16 *logits, float16 *loss_grad, int *labels, float16 *logits_grad, long long *params) .. c:function:: void fp_nll_loss_grad_p(float *logits, float *loss_grad, int *labels, float *logits_grad, long long *params) **C调用示例:** .. code-block:: c :linenos: :emphasize-lines: 15 // MT7004 示例(私有存储单核,AM 地址) void TestNllLossGradAMFp32(void) { float *logits = (float *)0x10010000; float *loss_grad = (float *)0x10020000; int *labels = (int *)0x10030000; float *weight = (float *)0x10040000; float *total_weight = (float *)0x10050000; float *logits_grad = (float *)0x10060000; long long params[5]; params[0] = (long long)weight; params[1] = (long long)total_weight; params[2] = 16; // batch params[3] = 16; // class_num params[4] = 2; // reduction_type = None fp_nll_loss_grad_p(logits, loss_grad, labels, logits_grad, params); } void main() { TestNllLossGradAMFp32(); }